﻿using System;
using System.Collections.Generic;
using System.Text;
using Haozes.FxClient.Core;

namespace Haozes.FxClient.Sip
{
    public class PacketFactory
    {
        private static long keepLiveCSeq = 2;
        public static User Ower;
        public static readonly string DEFAULT_URI = "fetion.com.cn";

        public static SipMessage GetPersonalInfo()
        {
            string msgContent = "<args><personal attributes=\"all\" /><services version=\"\" attributes=\"all\" /><config version=\"305\" attributes=\"all\" /><mobile-device attributes=\"all\" /></args>";
            SipRequest req = new SipRequest(SipMethodName.Service, DEFAULT_URI);
            SipHeadField hFrom = new SipHeadField(SipHeadFieldName.From, Ower.Uri.Sid.ToString());
            SipHeadField hCallID = new SipHeadField(SipHeadFieldName.CallID, Ower.Conncetion.NextCallID().ToString());
            SipHeadField hCSeq = new SipHeadField(SipHeadFieldName.CSeq, "1 " + SipMethodName.Service);
            SipHeadField hEvent = new SipHeadField(SipHeadFieldName.Event, "GetPersonalInfo");
            req.HeadFields.Add(hFrom);
            req.HeadFields.Add(hCallID);
            req.HeadFields.Add(hCSeq);
            req.HeadFields.Add(hEvent);
            req.Body = msgContent;
            return req;
        }

        public static SipMessage GetContactList()
        {

            string msgContent = "<args><contacts><buddy-lists /><buddies attributes=\"all\" /><mobile-buddies attributes=\"all\" /><chat-friends /><blacklist /></contacts></args>";
            SipRequest req = new SipRequest(SipMethodName.Service, DEFAULT_URI);
            SipHeadField hFrom = new SipHeadField(SipHeadFieldName.From, Ower.Uri.Sid.ToString());
            SipHeadField hCallID = new SipHeadField(SipHeadFieldName.CallID, Ower.Conncetion.NextCallID().ToString());
            SipHeadField hCSeq = new SipHeadField(SipHeadFieldName.CSeq, "1 " + SipMethodName.Service);
            SipHeadField hEvent = new SipHeadField(SipHeadFieldName.Event, "GetContactList");
            req.HeadFields.Add(hFrom);
            req.HeadFields.Add(hCallID);
            req.HeadFields.Add(hCSeq);
            req.HeadFields.Add(hEvent);
            req.Body = msgContent;
            return req;
        }

        private static string BuildGetContactsInfoText(IList<Contact> contactList)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("<args><contacts attributes=\"provisioning;impresa;mobile-no;nickname;name;portrait-crc;ivr-enabled;user-id\" extended-attributes=\"score-level\">");
            foreach (Contact c in contactList)
            {
                sb.Append(string.Format("<contact uri=\"{0}\" />", c.Uri.ToString()));
            }
            sb.Append("</contacts></args>");
            return sb.ToString();
        }

        public static SipMessage GetContactsInfo(IList<Contact> contactList)
        {
            string msgContent = BuildGetContactsInfoText(contactList);
            return GetContactsInfo(msgContent);
        }

        public static SipMessage GetContactsInfo(SipUri buddyUri)
        {
            string msgContent = string.Format("<args><contacts attributes=\"nickname\" extended-attributes=\"score-level\"><contact uri=\"{0}\" /></contacts></args>", buddyUri.ToString());
            return GetContactsInfo(msgContent);
        }

        private static SipMessage GetContactsInfo(string msgContent)
        {
            SipRequest req = new SipRequest(SipMethodName.Service, DEFAULT_URI);
            SipHeadField hFrom = new SipHeadField(SipHeadFieldName.From, Ower.Uri.Sid.ToString());
            SipHeadField hCallID = new SipHeadField(SipHeadFieldName.CallID, Ower.Conncetion.NextCallID().ToString());
            SipHeadField hCSeq = new SipHeadField(SipHeadFieldName.CSeq, "1 " + SipMethodName.Service);
            SipHeadField hEvent = new SipHeadField(SipHeadFieldName.Event, "GetContactsInfo");
            req.HeadFields.Add(hFrom);
            req.HeadFields.Add(hCallID);
            req.HeadFields.Add(hCSeq);
            req.HeadFields.Add(hEvent);
            req.Body = msgContent;
            return req;
        }

        public static SipMessage GetKeepLoginPacket()
        {
            SipRequest req = new SipRequest(SipMethodName.Register, DEFAULT_URI);
            SipHeadField hFrom = new SipHeadField(SipHeadFieldName.From, Ower.Uri.Sid.ToString());
            SipHeadField hCallID = new SipHeadField(SipHeadFieldName.CallID, "1");
            SipHeadField hCSeq = new SipHeadField(SipHeadFieldName.CSeq, NextKeepLiveCSeq());
            req.HeadFields.Add(hFrom);
            req.HeadFields.Add(hCallID);
            req.HeadFields.Add(hCSeq);
            req.Body = Environment.NewLine;
            return req;
        }

        public static SipMessage SMSPacket(SipUri sipUri, string msgContent)
        {
            SipRequest req = new SipRequest(SipMethodName.Message, DEFAULT_URI);
            SipHeadField hFrom = new SipHeadField(SipHeadFieldName.From, Ower.Uri.Sid.ToString());
            SipHeadField hCallID = new SipHeadField(SipHeadFieldName.CallID, Ower.Conncetion.NextCallID().ToString());
            SipHeadField hCSeq = new SipHeadField(SipHeadFieldName.CSeq, "1 " + SipMethodName.Message);
            SipHeadField hTo = new SipHeadField(SipHeadFieldName.To, sipUri.ToString());
            SipHeadField hEvent = new SipHeadField(SipHeadFieldName.Event, "SendSMS");
            req.HeadFields.Add(hFrom);
            req.HeadFields.Add(hCallID);
            req.HeadFields.Add(hCSeq);
            req.HeadFields.Add(hTo);
            req.HeadFields.Add(hEvent);
            req.Body = msgContent;
            return req;
        }

        public static SipMessage ReplyMsgPacket(SipMessage packet, string msgContent)
        {
            SipRequest req = new SipRequest(SipMethodName.Message, DEFAULT_URI);
            SipHeadField hFrom = new SipHeadField(SipHeadFieldName.From, Ower.Uri.Sid.ToString());
            SipHeadField hCallID = new SipHeadField(SipHeadFieldName.CallID, packet.CallID.Value);
            SipHeadField hCSeq = new SipHeadField(SipHeadFieldName.CSeq, packet.CSeq.Value);
            SipHeadField hTo = new SipHeadField(SipHeadFieldName.To, packet.To.Value);
            SipHeadField hContentType = new SipHeadField(SipHeadFieldName.ContentType, "text/html-fragment");
            SipHeadField hSupported = new SipHeadField(SipHeadFieldName.Supported, "SaveHistory");
            req.HeadFields.Add(hFrom);
            req.HeadFields.Add(hCallID);
            req.HeadFields.Add(hCSeq);
            req.HeadFields.Add(hTo);
            req.HeadFields.Add(hContentType);
            req.HeadFields.Add(hSupported);
            req.Body = msgContent;
            return req;
        }

        public static SipMessage ReplyMsgPacket(Conversation conv, string msgContent)
        {
            SipRequest req = new SipRequest(SipMethodName.Message, DEFAULT_URI);
            SipHeadField hFrom = new SipHeadField(SipHeadFieldName.From, Ower.Uri.Sid.ToString());
            SipHeadField hCallID = new SipHeadField(SipHeadFieldName.CallID, conv.CallID.ToString());
            SipHeadField hCSeq = new SipHeadField(SipHeadFieldName.CSeq, conv.CSeq);
            SipHeadField hTo = new SipHeadField(SipHeadFieldName.To, conv.From.ToString());
            SipHeadField hContentType = new SipHeadField(SipHeadFieldName.ContentType, "text/html-fragment");
            SipHeadField hSupported = new SipHeadField(SipHeadFieldName.Supported, "SaveHistory");
            req.HeadFields.Add(hFrom);
            req.HeadFields.Add(hCallID);
            req.HeadFields.Add(hCSeq);
            req.HeadFields.Add(hTo);
            req.HeadFields.Add(hContentType);
            req.HeadFields.Add(hSupported);
            req.Body = msgContent;
            return req;
        }

        public static SipMessage LeaveMsgPacket(SipUri sipUri, string msgContent)
        {
            SipRequest req = new SipRequest(SipMethodName.Message, DEFAULT_URI);
            SipHeadField hFrom = new SipHeadField(SipHeadFieldName.From, Ower.Uri.Sid.ToString());
            SipHeadField hCallID = new SipHeadField(SipHeadFieldName.CallID, Ower.Conncetion.NextCallID().ToString());
            SipHeadField hCSeq = new SipHeadField(SipHeadFieldName.CSeq, "2 M");
            SipHeadField hTo = new SipHeadField(SipHeadFieldName.To, sipUri.ToString());
            SipHeadField hContentType = new SipHeadField(SipHeadFieldName.ContentType, "text/plain");
            SipHeadField hSupported = new SipHeadField(SipHeadFieldName.Supported, "SaveHistory");
            req.HeadFields.Add(hFrom);
            req.HeadFields.Add(hCallID);
            req.HeadFields.Add(hCSeq);
            req.HeadFields.Add(hTo);
            req.HeadFields.Add(hContentType);
            req.HeadFields.Add(hSupported);
            req.Body = msgContent;
            return req;
        }

        public static SipMessage RSPInvitePacket(SipMessage packet)
        {
            System.Net.EndPoint localPoint = Ower.Conncetion.LocalEndPoint;
            string port = localPoint.ToString().Split(':')[1];

            StringBuilder sb = new StringBuilder();
            sb.AppendLine("v=0");
            sb.AppendLine("o=-0 0 IN " + localPoint.ToString());
            sb.AppendLine("s=session");
            sb.AppendLine("c=IN IP4 " + localPoint.ToString());
            sb.AppendLine("t=0 0");
            sb.AppendLine(string.Format("m=message {0} sip {1}", port, Ower.Uri.Sid));

            #region old

            //Internal req = new Internal(200,"OK");
            //SipHeadField hCallID = new SipHeadField(SipHeadFieldName.CallID, packet.CallID.Value);
            //SipHeadField hCSeq = new SipHeadField(SipHeadFieldName.CSeq, packet.CSeq.Value);
            //SipHeadField hFrom = new SipHeadField(SipHeadFieldName.From, packet.From.Value);
            //SipHeadField hSupported = new SipHeadField(SipHeadFieldName.Supported,packet.Supported.Value);

            //req.HeadFields.Add(hFrom);
            //req.HeadFields.Add(hCallID);
            //req.HeadFields.Add(hCSeq);
            //req.HeadFields.Add(hSupported);

            #endregion
            SipResponse response = CreateDefaultResponse(packet);
            response.Body = sb.ToString();
            return response;
        }

        public static SipMessage RSPReceiveMsgPacket(SipMessage packet)
        {
            #region old

            //SipMessage p = new SipMessage();
            //SipcHead header = new SipcHead();
            //header.SipMethod = SipMethodName.Empty;
            //header.SipMethodTarget = SipcHead.SuccessTarget;
            //header[SipHeadFieldName.From] = packet.Head[SipHeadFieldName.From];
            //header[SipHeadFieldName.CallID] = packet.Head[SipHeadFieldName.CallID];
            //header[SipHeadFieldName.CSeq] = packet.Head[SipHeadFieldName.CSeq];

            //p.Head = header;
            //p.Body = Environment.NewLine;
            //return p;

            #endregion
            return CreateDefaultResponse(packet);
        }

        public static SipMessage RSPBye(SipMessage packet)
        {
            #region old

            //SipMessage p = new SipMessage();
            //SipcHead header = new SipcHead();
            //p.Head = header;
            //header.SipMethod = SipMethodName.Empty;
            //header.SipMethodTarget = SipcHead.SuccessTarget;
            //header[SipHeadFieldName.From] = packet.Head[SipHeadFieldName.From];
            //header[SipHeadFieldName.CallID] = packet.Head[SipHeadFieldName.CallID];
            //header[SipHeadFieldName.CSeq] = packet.Head[SipHeadFieldName.CSeq];

            //p.Head = header;
            //p.Body = Environment.NewLine;

            //return p;

            #endregion
            return CreateDefaultResponse(packet);
        }

        private static string NextKeepLiveCSeq()
        {
            return ++keepLiveCSeq + " " + SipMethodName.Register;
        }

        private static SipResponse CreateDefaultResponse(SipMessage packet)
        {
            SipResponse response = new SipResponse(200, "OK");
            SipHeadField hCallID = new SipHeadField(SipHeadFieldName.CallID, packet.CallID.Value);
            SipHeadField hCSeq = new SipHeadField(SipHeadFieldName.CSeq, packet.CSeq.Value);
            SipHeadField hFrom = new SipHeadField(SipHeadFieldName.From, packet.From.Value);
            if (packet.To != null)
            {
                SipHeadField hTo = new SipHeadField(SipHeadFieldName.To, packet.To.Value);
                response.HeadFields.Add(hTo);
            }
            if (packet.Supported != null)
            {
                SipHeadField hSupported = new SipHeadField(SipHeadFieldName.Supported, packet.Supported.Value);
                response.HeadFields.Add(hSupported);
            }
            response.HeadFields.Add(hFrom);
            response.HeadFields.Add(hCallID);
            response.HeadFields.Add(hCSeq);

            response.Body = Environment.NewLine;

            return response;
        }

        public static SipMessage HandleContactRequest(SipUri buddyUri)
        {
            string msgContent = string.Format("<args><contacts><buddies><buddy uri=\"{0}\" result=\"1\" buddy-lists=\"\" expose-mobile-no=\"0\" expose-name=\"0\" /></buddies></contacts></args>", buddyUri.ToString());
            SipRequest req = new SipRequest(SipMethodName.Service, DEFAULT_URI);
            SipHeadField hFrom = new SipHeadField(SipHeadFieldName.From, Ower.Uri.Sid.ToString());
            SipHeadField hCallID = new SipHeadField(SipHeadFieldName.CallID, Ower.Conncetion.NextCallID().ToString());
            SipHeadField hCSeq = new SipHeadField(SipHeadFieldName.CSeq, "1 " + SipMethodName.Service);
            SipHeadField hEvent = new SipHeadField(SipHeadFieldName.Event, "HandleContactRequest");
            req.HeadFields.Add(hFrom);
            req.HeadFields.Add(hCallID);
            req.HeadFields.Add(hCSeq);
            req.HeadFields.Add(hEvent);
            req.Body = msgContent;
            return req;
        }

        public static SipMessage AddBuddy(SipUri buddyUri, string desc)
        {
            if (string.IsNullOrEmpty(desc))
                desc = Ower.NickName;
            string msgContent = string.Format("<args><contacts><buddies><buddy uri=\"{0}\" buddy-lists=\"\" desc=\"{1}\" expose-mobile-no=\"1\" expose-name=\"1\" /></buddies></contacts></args>", buddyUri.ToString(), desc);
            SipRequest req = new SipRequest(SipMethodName.Service, DEFAULT_URI);
            SipHeadField hFrom = new SipHeadField(SipHeadFieldName.From, Ower.Uri.Sid.ToString());
            SipHeadField hCallID = new SipHeadField(SipHeadFieldName.CallID, Ower.Conncetion.NextCallID().ToString());
            SipHeadField hCSeq = new SipHeadField(SipHeadFieldName.CSeq, "1 " + SipMethodName.Service);
            SipHeadField hEvent = new SipHeadField(SipHeadFieldName.Event, "AddBuddy");
            req.HeadFields.Add(hFrom);
            req.HeadFields.Add(hCallID);
            req.HeadFields.Add(hCSeq);
            req.HeadFields.Add(hEvent);
            req.Body = msgContent;
            return req;
        }

        public static SipMessage AddMobileBuddy(SipUri buddyUri, string desc)
        {
            if (string.IsNullOrEmpty(desc))
                desc = Ower.NickName;
            string msgContent = string.Format("<args><contacts><mobile-buddies><mobile-buddy uri=\"{0}\" buddy-lists=\"1\" desc=\"{1}\" invite=\"0\" /></mobile-buddies></contacts></args>", buddyUri.ToString(), desc);
            SipRequest req = new SipRequest(SipMethodName.Service, DEFAULT_URI);
            SipHeadField hFrom = new SipHeadField(SipHeadFieldName.From, Ower.Uri.Sid.ToString());
            SipHeadField hCallID = new SipHeadField(SipHeadFieldName.CallID, Ower.Conncetion.NextCallID().ToString());
            SipHeadField hCSeq = new SipHeadField(SipHeadFieldName.CSeq, "1 " + SipMethodName.Service);
            SipHeadField hEvent = new SipHeadField(SipHeadFieldName.Event, "AddMobileBuddy");
            req.HeadFields.Add(hFrom);
            req.HeadFields.Add(hCallID);
            req.HeadFields.Add(hCSeq);
            req.HeadFields.Add(hEvent);
            req.Body = msgContent;
            return req;
        }

        public static SipMessage DeleteBuddy(SipUri buddyUri)
        {
            string msgContent = string.Format("<args><contacts><buddies><buddy uri=\"{0}\" /></buddies></contacts></args>", buddyUri.ToString());
            SipRequest req = new SipRequest(SipMethodName.Service, DEFAULT_URI);
            SipHeadField hFrom = new SipHeadField(SipHeadFieldName.From, Ower.Uri.Sid.ToString());
            SipHeadField hCallID = new SipHeadField(SipHeadFieldName.CallID, Ower.Conncetion.NextCallID().ToString());
            SipHeadField hCSeq = new SipHeadField(SipHeadFieldName.CSeq, "1 " + SipMethodName.Service);
            SipHeadField hEvent = new SipHeadField(SipHeadFieldName.Event, "DeleteBuddy");
            req.HeadFields.Add(hFrom);
            req.HeadFields.Add(hCallID);
            req.HeadFields.Add(hCSeq);
            req.HeadFields.Add(hEvent);
            req.Body = msgContent;
            return req;
        }

        public static SipMessage DeleteMobileBuddy(SipUri mobileBuddyUri)
        {
            string msgContent = string.Format("<args><contacts><mobile-buddies><mobile-buddy uri=\"{0}\" /></mobile-buddies></contacts></args>", mobileBuddyUri.ToString());
            SipRequest req = new SipRequest(SipMethodName.Service, DEFAULT_URI);
            SipHeadField hFrom = new SipHeadField(SipHeadFieldName.From, Ower.Uri.Sid.ToString());
            SipHeadField hCallID = new SipHeadField(SipHeadFieldName.CallID, Ower.Conncetion.NextCallID().ToString());
            SipHeadField hCSeq = new SipHeadField(SipHeadFieldName.CSeq, "1 " + SipMethodName.Service);
            SipHeadField hEvent = new SipHeadField(SipHeadFieldName.Event, "DeleteMobileBuddy");
            req.HeadFields.Add(hFrom);
            req.HeadFields.Add(hCallID);
            req.HeadFields.Add(hCSeq);
            req.HeadFields.Add(hEvent);
            req.Body = msgContent;
            return req;
        }
    }
}
